<?php

declare(strict_types=1);

namespace App\Fastapp\Job;

use App\Fastapp\Api\Service\Crypto\Coin\Btc;
use App\Fastapp\Api\Service\Crypto\Coin\Ton;
use App\Fastapp\Api\Service\Crypto\Config;
use App\Fastapp\Model\AccountWalletAddress;
use App\Fastapp\Model\AccountWallet;
use App\Fastapp\Model\Currency;
use Hyperf\AsyncQueue\Job;

class WalletAddressJob extends Job
{
    public function __construct(public int $user_id, public string $symbol)
    {
    }

    public function handle(): void
    {
        $symbols = explode(',', $this->symbol);
        foreach (Currency::query()->where(['type' => 2])->whereIn('symbol', $symbols)->get() as $item) {
            $up = [];
            if ($item->symbol == 'TRX') $up = $this->genTrxAddress();
            if ($item->symbol == 'BNB') $up = $this->genBnbAddress();
            if ($item->symbol == 'ETH') $up = $this->genEthAddress();
            if ($item->symbol == 'BTC') $up = $this->genBtcAddress();
            if ($item->symbol == 'FIL') $up = $this->genFileAddress();
            if ($item->symbol == 'TON') $up = $this->genTonAddress();
            if ($up) AccountWallet::query()->where(['user_id' => $this->user_id, 'symbol' => $item->symbol])->update($up);
        }
    }

    public function createWalletAddress(array $data): AccountWalletAddress
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => $data['symbol']])->first();
        if ($md) return $md;
        $data['user_id'] = $this->user_id;
        return AccountWalletAddress::query()->create($data);
    }

    public function genBtcAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'BTC'])->first();
        if (!$md) {
            list($address, $private) = Btc::genAddress();
            $md = $this->createWalletAddress([
                'symbol' => 'BTC',
                'address' => $address,
                'private_key' => $private
            ]);
        }
        return ['address' => $md->address];
    }

    public function genTrxAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'TRX'])->first();
        if (!$md) {
            $trxWallet = new \TronApi\TRX(Config::TRX_URL);
            $addressData = $trxWallet->generateAddress();
            $md = $this->createWalletAddress([
                'symbol' => 'TRX',
                'address' => $addressData['wallet'],
                'private_key' => $addressData['privatekey']
            ]);
        }
        return ['address' => $md->address];
    }

    public function genEthAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'ETH'])->first();
        if (!$md) {
            $util = new \Web3p\EthereumUtil\Util();
            $privateKey = bin2hex(random_bytes(32));
            $publicKey = $util->privateKeyToPublicKey($privateKey);
            $address = $util->publicKeyToAddress($publicKey);
            $md = $this->createWalletAddress([
                'symbol' => 'ETH',
                'address' => $address,
                'private_key' => $privateKey
            ]);
        }
        return ['address' => $md->address];
    }

    public function genFileAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'FIL'])->first();
        if (!$md) {
            $address = new \He426100\Filecoin\Address();
            $address->currentNetwork = \He426100\Filecoin\Address::MAINNET;
            $md = $this->createWalletAddress([
                'symbol' => 'FIL',
                'address' => $address->get(),
                'private_key' => $address->getPrivateKey()
            ]);
        }
        return ['address' => $md->address];
    }

    public function genBnbAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'BNB'])->first();
        if (!$md) {
            $wallet = new \Binance\Wallet();
            $address = $wallet->newAccountByMnemonic();
            $md = $this->createWalletAddress([
                'symbol' => 'BNB',
                'address' => $address['address'],
                'private_key' => $address['key']
            ]);
        }
        return ['address' => $md->address];
    }

    public function genTonAddress(): array
    {
        $md = AccountWalletAddress::query()->where(['user_id' => $this->user_id, 'symbol' => 'TON'])->first();
        if (!$md) {
            list($address, $private) = Ton::genAddress();
            $md = $this->createWalletAddress([
                'symbol' => 'TON',
                'address' => $address,
                'private_key' => $private
            ]);
        }
        return ['address' => $md->address];
    }
}
